
/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package doghost.controllers;

import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.persistence.EntityManager;
import javax.persistence.RollbackException;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import doghost.DoghostApp;
import doghost.editors.FaturamentoEditor;
import doghost.editors.HospedagemEditor;
import doghost.entities.Diaria;
import doghost.entities.Hospedagem;
import doghost.entities.ItemDeHospedagem;
import doghost.utils.CustomUserDialog;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.concurrent.TimeUnit;
import javax.persistence.Query;

/**
 *
 * @author duo
 */
public class HospedagemController {
    protected Hospedagem hospedagem;
    protected boolean operationOk;

    public Hospedagem getHospedagem() {
        return hospedagem;
    }

    public void setHospedagem(Hospedagem hospedagem) {
        this.hospedagem = hospedagem;
    }

    /**
     * Get the value of operationOk
     *
     * @return the value of operationOk
     */
    public boolean isOperationOk() {
        return operationOk;
    }

    /**
     * Set the value of operationOk
     *
     * @param operationOk new value of operationOk
     */
    public void setOperationOk(boolean operationOk) {
        this.operationOk = operationOk;
    }

    public void newHospedagem(EntityManager entityManager, List list) {
        // create a transient object
        this.setOperationOk(false);
        setHospedagem(new Hospedagem());
        this.getHospedagem().setInicio(new java.util.Date());
        JFrame mainFrame = DoghostApp.getApplication().getMainFrame();
        HospedagemEditor hospedagemEditor = new HospedagemEditor(mainFrame, true);
        hospedagemEditor.setLocationRelativeTo(mainFrame);
        hospedagemEditor.setCurrentRecord(getHospedagem());
        hospedagemEditor.setVisible(true);
        if (hospedagemEditor.isSaveFired()) {
            try {
                entityManager.getTransaction().begin();

                entityManager.persist(getHospedagem());
                entityManager.getTransaction().commit();
                /*
                if (hospedagemEditor.isItemsChanged()) {
                    // atualizar a lista
                    Query query = entityManager.createQuery("SELECT i " +
                            " FROM ItemDeHospedagem i WHERE i.id = :id").
                            setHint("toplink.refresh", "true").
                            setParameter("id", this.getHospedagem().getId());
                    List<ItemDeHospedagem> listaHospedagem = query.getResultList();
                    this.getHospedagem().setItensDeHospedagem(listaHospedagem);
                }
                */
                this.setOperationOk(true);
                if(list != null) {
                    list.add(getHospedagem());
                }
                Logger.getLogger(this.getClass().getName()).
                        log(Level.INFO, "Hospedagem adicionado(a) com sucesso: " +
                        getHospedagem());
            }
            catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                        log(Level.SEVERE, "Erro adicionando Hospedagem: " + e);
            }
        }
    }

    public void editHospedagem(EntityManager entityManager, List list, int index) {
        this.setOperationOk(false);
        // atualizar a lista
        Query query = entityManager.createQuery("SELECT i " +
                " FROM ItemDeHospedagem i WHERE i.hospedagem = :hospedagem").
                setHint("toplink.refresh", "true").
                setParameter("hospedagem", this.getHospedagem());
        List<ItemDeHospedagem> freshListaHospedagem = query.getResultList();
        // atualizar a Hospedagem
        query = entityManager.createQuery("SELECT h " +
                " FROM Hospedagem h WHERE h.id = :id").
                setHint("toplink.refresh", "true").
                setParameter("id", this.getHospedagem().getId());
        Hospedagem freshHospedagem = (Hospedagem) query.getSingleResult();
        if (freshHospedagem != null) {
            freshHospedagem.setItensDeHospedagem(freshListaHospedagem);
            this.setHospedagem(freshHospedagem);
        }
        entityManager.getTransaction().begin();
        JFrame mainFrame = DoghostApp.getApplication().getMainFrame();
        HospedagemEditor hospedagemEditor = new HospedagemEditor(mainFrame, true);
        hospedagemEditor.setLocationRelativeTo(mainFrame);
        hospedagemEditor.setCurrentRecord(getHospedagem());
        hospedagemEditor.setVisible(true);
        /*
         * Things changed, now we wish to save changes on items
         * only if the head is saved.
        if (hospedagemEditor.isSaveFired() || 
                hospedagemEditor.isItemsChanged()) {
        */
        if (hospedagemEditor.isSaveFired()) {
            try {
                List<ItemDeHospedagem> removedItensDeHospedagem =
                        hospedagemEditor.getRemovedItensDeHospedagem();
                if (removedItensDeHospedagem != null) {
                    for (ItemDeHospedagem item : removedItensDeHospedagem) {
                        entityManager.remove(item);
                    }
                }
                entityManager.merge(getHospedagem());
                entityManager.getTransaction().commit();
                this.setOperationOk(true);
                Logger.getLogger(this.getClass().getName()).
                    log(Level.INFO, "Hospedagem Editado(a) com sucesso: " +
                    getHospedagem());
            } catch (RollbackException rex) {
                // refresh hospedagem in list
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Hospedagem erro de edição (rollback) : " +
                    rex);
                Hospedagem originalHospedagem = (Hospedagem)
                        entityManager.find(getHospedagem().getClass(),
                        getHospedagem().getId());
                if(list != null) {
                    list.remove(getHospedagem());
                    list.add(index, originalHospedagem);
                }
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                        log(Level.SEVERE, "Hospedagem erro de edição: " + e);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando edição de hospedagem, " +
                                "transação ativa: " + erb);
                    }
                }
            }
        } else {
            try {
                if (entityManager.getTransaction().isActive()) {
                    entityManager.getTransaction().rollback();
                    /*
                    entityManager.refresh(getHospedagem());
                    entityManager.getTransaction().commit();
                    */
                }
                // atualizar a lista
                freshListaHospedagem = query.getResultList();
                // atualizar a Hospedagem
                freshHospedagem = (Hospedagem) query.getSingleResult();
                if (freshHospedagem != null) {
                    freshHospedagem.setItensDeHospedagem(freshListaHospedagem);
                    this.setHospedagem(freshHospedagem);
                }
                if(list != null) {
                    list.remove(getHospedagem());
                    list.add(index, freshHospedagem);
                }
                Logger.getLogger(this.getClass().getName()).
                    log(Level.INFO, " Edição de Hospedagem cancelada com sucesso " +
                    "hospedagem: " + getHospedagem());
            } catch (RollbackException rex) {
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Erro cancelando edição de hospedagem " +
                    "(rollback) : " + rex);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando eliminação de hospedagem. " +
                                "transação ativa: " + erb);
                    }
                }
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                        log(Level.SEVERE, "Hospedagem erro de edição: " + e);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando edição de hospedagem, " +
                                "transação ativa: " + erb);
                    }
                }
            }
        }
    }

    public void faturarHospedagem(EntityManager entityManager, List list, int index) {
        this.setOperationOk(false);
        // atualizar a lista
        Query query = entityManager.createQuery("SELECT i " +
                " FROM ItemDeHospedagem i WHERE i.hospedagem = :hospedagem").
                setHint("toplink.refresh", "true").
                setParameter("hospedagem", this.getHospedagem());
        List<ItemDeHospedagem> freshListaHospedagem = query.getResultList();
        // atualizar valor dos itens
        Double valorItens = new Double("0.00");
        for(ItemDeHospedagem i : freshListaHospedagem) {
            valorItens += i.getValor() * i.getQuantidade();
        }
        // atualizar a Hospedagem
        query = entityManager.createQuery("SELECT h " +
                " FROM Hospedagem h WHERE h.id = :id").
                setHint("toplink.refresh", "true").
                setParameter("id", this.getHospedagem().getId());
        Hospedagem freshHospedagem = (Hospedagem) query.getSingleResult();
        if (freshHospedagem != null) {
            freshHospedagem.setItensDeHospedagem(freshListaHospedagem);
            this.setHospedagem(freshHospedagem);
        }
        // setar uma data para o faturamento, se não houver
        if(this.getHospedagem().getFaturamento() == null) {
            this.getHospedagem().setFaturamento(new java.util.Date());
        }
        // setar um valor para as diárias, se não houver
        if(this.getHospedagem().getValorDiaria() == null || 
                this.getHospedagem().getValorDiaria().doubleValue() == new Double("0.00").doubleValue()) {
            query = entityManager.createQuery("SELECT d FROM Diaria d ORDER BY " +
                    "d.inicio DESC").
                setHint("toplink.refresh", "true");
            try {
                Diaria d = (Diaria) query.getResultList().get(0);
                this.getHospedagem().setValorDiaria(d.getValor());
            } catch (Exception e) {
                this.getHospedagem().setValorDiaria(new Double("0.00"));
                Logger.getLogger(this.getClass().getName()).
                        log(Level.WARNING, "Falha ao tentar ler o valor de diária mais recente (verifique a tabela!): " + e);
            }
        }
        // setar valor para a quantidade de diárias, se não houver
        if(this.getHospedagem().getDiarias() == null || this.getHospedagem().getDiarias().intValue() == 0) {
            this.getHospedagem().setDiarias(calcularDiarias(this.getHospedagem().getInicio(),
                    this.getHospedagem().getFim()));
        }
        if(this.getHospedagem().getValor() == null ||
                this.getHospedagem().getValor().doubleValue() == new Double("0.00").doubleValue()) {
            Double valor = new Double("0.00");
            valor += this.getHospedagem().getDiarias() * this.getHospedagem().getValorDiaria();
            valor += valorItens;
            this.getHospedagem().setValor(valor);
        }
        if(this.getHospedagem().getDesconto() == null) {
            this.getHospedagem().setDesconto(new Double("0.00"));
        }
        if(this.getHospedagem().getJuros() == null) {
            this.getHospedagem().setJuros(new Double("0.00"));
        }
        entityManager.getTransaction().begin();
        JFrame mainFrame = DoghostApp.getApplication().getMainFrame();
        FaturamentoEditor faturamentoEditor = new FaturamentoEditor(mainFrame, true);
        faturamentoEditor.setLocationRelativeTo(mainFrame);
        faturamentoEditor.setCurrentRecord(getHospedagem());
        faturamentoEditor.setValorItens(valorItens);
        faturamentoEditor.setVisible(true);
        if (faturamentoEditor.isSaveFired()) {
            try {
                entityManager.merge(getHospedagem());
                entityManager.getTransaction().commit();
                this.setOperationOk(true);
                Logger.getLogger(this.getClass().getName()).
                    log(Level.INFO, "Hospedagem faturada com sucesso: " +
                    getHospedagem());
            } catch (RollbackException rex) {
                // refresh hospedagem in list
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Hospedagem erro de faturamento (rollback) : " +
                    rex);
                Hospedagem originalHospedagem = (Hospedagem)
                        entityManager.find(getHospedagem().getClass(),
                        getHospedagem().getId());
                if(list != null) {
                    list.remove(getHospedagem());
                    list.add(index, originalHospedagem);
                }
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                        log(Level.SEVERE, "Hospedagem erro de faturamento: " + e);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando faturamento de hospedagem, " +
                                "transação ativa: " + erb);
                    }
                }
            }
        } else {
            try {
                if (entityManager.getTransaction().isActive()) {
                    entityManager.refresh(getHospedagem());
                    entityManager.getTransaction().commit();
                }
                // refresh hospedagem in list
                Hospedagem originalHospedagem = (Hospedagem)
                        entityManager.find(getHospedagem().getClass(),
                        getHospedagem().getId());
                if(list != null) {
                    list.remove(getHospedagem());
                    list.add(index, originalHospedagem);
                }
                Logger.getLogger(this.getClass().getName()).
                    log(Level.INFO, " Faturamento de Hospedagem cancelada com sucesso " +
                    "hospedagem: " + getHospedagem());
            } catch (RollbackException rex) {
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Erro cancelando faturamento de hospedagem " +
                    "(rollback) : " + rex);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando faturmaento de hospedagem. " +
                                "transação ativa: " + erb);
                    }
                }
            }
        }
    }

    public void receberHospedagem(EntityManager entityManager, List list, int index) {
        this.setOperationOk(false);
        // atualizar a lista
        Query query = entityManager.createQuery("SELECT i " +
                " FROM ItemDeHospedagem i WHERE i.hospedagem = :hospedagem").
                setHint("toplink.refresh", "true").
                setParameter("hospedagem", this.getHospedagem());
        List<ItemDeHospedagem> freshListaHospedagem = query.getResultList();
        // atualizar a Hospedagem
        query = entityManager.createQuery("SELECT h " +
                " FROM Hospedagem h WHERE h.id = :id").
                setHint("toplink.refresh", "true").
                setParameter("id", this.getHospedagem().getId());
        Hospedagem freshHospedagem = (Hospedagem) query.getSingleResult();
        if (freshHospedagem != null) {
            freshHospedagem.setItensDeHospedagem(freshListaHospedagem);
            this.setHospedagem(freshHospedagem);
        }
        if(this.getHospedagem().getFaturamento() == null) {
            CustomUserDialog.avisar("Não se pode baixar hospedagem não faturada, realize a ação faturar antes.");
            return;
        }
        if(this.getHospedagem().getPagamento() == null) {
            this.getHospedagem().setPagamento(new Date());
        }
        entityManager.getTransaction().begin();
            try {
                entityManager.merge(getHospedagem());
                entityManager.getTransaction().commit();
                this.setOperationOk(true);
                Logger.getLogger(this.getClass().getName()).
                    log(Level.INFO, "Hospedagem baixada com sucesso: " +
                    getHospedagem());
            } catch (RollbackException rex) {
                // refresh hospedagem in list
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Hospedagem erro de baixa (rollback) : " +
                    rex);
                Hospedagem originalHospedagem = (Hospedagem)
                        entityManager.find(getHospedagem().getClass(),
                        getHospedagem().getId());
                if(list != null) {
                    list.remove(getHospedagem());
                    list.add(index, originalHospedagem);
                }
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                        log(Level.SEVERE, "Hospedagem erro de baixa: " + e);
                if (entityManager.getTransaction().isActive()) {
                    try {
                        entityManager.getTransaction().rollback();
                    } catch (Exception erb) {
                        Logger.getLogger(this.getClass().getName()).
                                log(Level.SEVERE, "Erro abandonando baixa de hospedagem, " +
                                "transação ativa: " + erb);
                    }
                }
            }
    }

    public void deleteHospedagem(EntityManager entityManager, List list, int index) {
        this.setOperationOk(false);
        Object[] options = {"Sim", "Não"};
        int n = JOptionPane.showOptionDialog(null, "Remove a linha ?", "Aviso",
                JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE, null, options, null);
        if (n ==JOptionPane.YES_OPTION) {
            try {
                entityManager.getTransaction().begin();
                entityManager.remove(getHospedagem());
                entityManager.getTransaction().commit();
                this.setOperationOk(true);
                if(list != null) {
                    list.remove(getHospedagem());
                }
            } catch (Exception e) {
                Logger.getLogger(this.getClass().getName()).
                    log(Level.SEVERE, "Erro eliminando hospedagem: " + e);
            }
        }
    }

    public int calcularDiarias(Date dtInicio, Date dtFim) {
        GregorianCalendar fim = new GregorianCalendar();
        fim.setTime(dtFim);
        GregorianCalendar inicio = new GregorianCalendar();
        inicio.setTime(dtInicio);
        GregorianCalendar prv = new GregorianCalendar();
        prv.setTime(dtInicio);
        // ignorar segundos e milisegundos
        fim.set(Calendar.SECOND, 0);
        fim.set(Calendar.MILLISECOND, 0);
        prv.set(Calendar.SECOND, 0);
        prv.set(Calendar.MILLISECOND, 0);
        inicio.set(Calendar.SECOND, 0);
        inicio.set(Calendar.MILLISECOND, 0);
        // verifica overhead no fim
        prv.set(Calendar.HOUR, fim.get(Calendar.HOUR));
        prv.set(Calendar.MINUTE, fim.get(Calendar.MINUTE));
        prv.setLenient(true);
        // retira 4 horas de tolerância
        prv.set(Calendar.HOUR, prv.get(Calendar.HOUR) -4);
        // prv agora possui a mesma data do inicio, com o horario do fim
        int dayOverhead = 0;
        if (prv.getTimeInMillis() > inicio.getTimeInMillis()) {
            dayOverhead = 1;
        }
        // ajusta o horário para que o fim coincida com o do inicio
        fim.set(Calendar.HOUR, inicio.get(Calendar.HOUR));
        fim.set(Calendar.MINUTE, inicio.get(Calendar.MINUTE));

        long dias = TimeUnit.DAYS.convert(fim.getTimeInMillis() - inicio.getTimeInMillis(), TimeUnit.MILLISECONDS);
        dias += dayOverhead;
        return (int) dias;
    }

}
